@tandryukha/aidemo 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/record-demo/SKILL.md +66 -0
- package/LICENSE +21 -0
- package/README.md +292 -0
- package/bin/aidemo.mjs +53 -0
- package/docs/AUTHORING.md +728 -0
- package/package.json +47 -0
- package/src/caption-render.ts +69 -0
- package/src/captions.ts +441 -0
- package/src/capture.ts +574 -0
- package/src/cards.ts +67 -0
- package/src/cli.ts +646 -0
- package/src/compose.ts +937 -0
- package/src/config.ts +222 -0
- package/src/cursor-overlay.ts +186 -0
- package/src/cursor.ts +134 -0
- package/src/distribute.ts +713 -0
- package/src/embed.ts +202 -0
- package/src/ffmpeg.ts +83 -0
- package/src/gif.ts +65 -0
- package/src/golden.ts +109 -0
- package/src/i18n.ts +86 -0
- package/src/mcp/jobs.ts +285 -0
- package/src/mcp/server.ts +1016 -0
- package/src/music.ts +153 -0
- package/src/params.ts +134 -0
- package/src/player.ts +1173 -0
- package/src/project.ts +287 -0
- package/src/recorder.ts +320 -0
- package/src/starter.ts +141 -0
- package/src/stills.ts +121 -0
- package/src/types.ts +660 -0
- package/src/util.ts +171 -0
- package/src/variants.ts +117 -0
- package/src/voice-local.ts +230 -0
- package/src/voice.ts +405 -0
- package/src/zoom.ts +183 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: record-demo
|
|
3
|
+
description: >
|
|
4
|
+
Produce a short (30-60s) narrated, captioned product demo video with the aidemo
|
|
5
|
+
engine, via the aidemo MCP server. Use when the user says "record a demo of X",
|
|
6
|
+
"make a demo video", "demo this feature", or points at a flow (e.g. a shopping
|
|
7
|
+
flow inside a ChatGPT app) and wants a shareable MP4 with voiceover + captions.
|
|
8
|
+
The skill authors a storyboard.json (script + per-scene voice/music plan +
|
|
9
|
+
browser action-spec) and renders it with the engine. Do NOT use for: live
|
|
10
|
+
screen-sharing, editing an already-rendered MP4, or demos of native/mobile
|
|
11
|
+
apps (browser only).
|
|
12
|
+
allowed-tools: Bash, Read, Write, Edit, Glob, Grep
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# record-demo
|
|
16
|
+
|
|
17
|
+
You are the **demo director**. Turn a feature + loose directions into a polished
|
|
18
|
+
browser demo video using the `aidemo` engine.
|
|
19
|
+
|
|
20
|
+
This file is a thin adapter. **The authoring knowledge lives in the engine** —
|
|
21
|
+
fetch it first, then follow it:
|
|
22
|
+
|
|
23
|
+
1. **Preferred — the `aidemo` MCP server** (registered by `aidemo repo-init`,
|
|
24
|
+
or bundled automatically if you installed the Claude Code plugin): call the
|
|
25
|
+
**`get_authoring_guide`** tool
|
|
26
|
+
and follow the guide. Pipeline operations (`probe`, `render`, `voice`,
|
|
27
|
+
`captions`, `compose`, `gif`) are **jobs**: they return a `jobId`
|
|
28
|
+
immediately — poll **`job_status`** for progress, results, and failure
|
|
29
|
+
artifacts. Validate storyboard edits with **`validate_storyboard`** before
|
|
30
|
+
rendering. Pass **absolute** demo directories.
|
|
31
|
+
2. **Fallback — no MCP server registered**: run `aidemo guide` and follow the
|
|
32
|
+
same document using the CLI commands it maps out.
|
|
33
|
+
3. **After verifying the final video** (per the guide's "Verify before
|
|
34
|
+
declaring done"): if you hit any engine bug, surprise, or workaround this
|
|
35
|
+
session, file it now — the MCP **`feedback`** tool (`title` + `body`;
|
|
36
|
+
environment/log context is auto-attached) or `aidemo feedback <dir>` on the
|
|
37
|
+
CLI (falls back to a local `docs/feedback-*.md` offline). If nothing came
|
|
38
|
+
up, skip this step.
|
|
39
|
+
|
|
40
|
+
## Invoking the engine (`aidemo`)
|
|
41
|
+
|
|
42
|
+
**`aidemo <cmd>`** means whichever of these applies:
|
|
43
|
+
- **In the aidemo repo itself** (a full checkout): `node bin/aidemo.mjs <cmd>`.
|
|
44
|
+
- **In a product repo** where this skill was installed via `aidemo repo-init`
|
|
45
|
+
(the engine is *not* vendored here): `npx -y github:tandryukha/aidemo#stable <cmd>`.
|
|
46
|
+
|
|
47
|
+
If unsure, run `aidemo doctor` (or the MCP `doctor` tool) — it prints the
|
|
48
|
+
engine version and checks prereqs (ffmpeg, Chrome, `OPENAI_API_KEY` — or
|
|
49
|
+
`OPENAI_BASE_URL` pointing at a local OpenAI-compatible server, or
|
|
50
|
+
`AIDEMO_TTS_PROVIDER=local` for in-process TTS + offline captions; in both
|
|
51
|
+
cases no key is needed and doctor reports what's in effect).
|
|
52
|
+
|
|
53
|
+
## Distribution & updates
|
|
54
|
+
|
|
55
|
+
This skill is a **versioned copy** of the source in the
|
|
56
|
+
[aidemo](https://github.com/tandryukha/aidemo) repo. In a product repo
|
|
57
|
+
it arrived via `aidemo repo-init`, which also added a `SessionStart` hook that
|
|
58
|
+
runs `aidemo skill check` and prints a notice when a newer version is out.
|
|
59
|
+
(The authoring guide itself never goes stale — it is served by the engine at
|
|
60
|
+
render time.)
|
|
61
|
+
- **Update the skill** (when notified, or any time): `aidemo skill update --dir .`
|
|
62
|
+
— rewrites this file and bumps `.claude/skills/record-demo/installed.json`.
|
|
63
|
+
Installed as a Claude Code plugin instead? Update it with `/plugin` (the
|
|
64
|
+
marketplace flow), not `aidemo skill update`.
|
|
65
|
+
- **Send feedback upstream**: see step 3 above.
|
|
66
|
+
- **Bootstrap a new repo**: `npx -y github:tandryukha/aidemo#stable repo-init --dir .`
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andrii Taran
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# aidemo — your coding agent makes the demo video
|
|
2
|
+
|
|
3
|
+
**[aidemo.top](https://aidemo.top)** · [watch a real 51s output ▶](https://github.com/tandryukha/aidemo/releases/download/v0.3.0/wikipedia-showcase-demo.mp4) · [authoring guide](docs/AUTHORING.md) · [render in CI](docs/CI.md)
|
|
4
|
+
|
|
5
|
+
Tell your coding agent *"record a 45s demo of the checkout flow"* — get back a
|
|
6
|
+
polished **MP4 with voiceover, synced captions, and auto-zoom**. Any MCP-capable
|
|
7
|
+
agent (Claude Code, Codex CLI, Gemini CLI) writes one `storyboard.json`; the
|
|
8
|
+
headless engine drives a real Chrome, records a **deterministic replay**, voices
|
|
9
|
+
it, captions it, and trims the dead time. Because the replay is deterministic,
|
|
10
|
+
**the demo re-renders itself in CI** when the product changes — no re-recording,
|
|
11
|
+
no API key, about **$0 a render**. An **open-source (MIT) alternative to Screen
|
|
12
|
+
Studio, Clueso, or Demosmith** for when you'd rather your coding agent make the
|
|
13
|
+
demo.
|
|
14
|
+
|
|
15
|
+
[](https://aidemo.top)
|
|
16
|
+
[](https://github.com/tandryukha/aidemo/actions/workflows/ci.yml)
|
|
17
|
+
[](LICENSE)
|
|
18
|
+
[](https://github.com/tandryukha/aidemo/releases)
|
|
19
|
+
[](https://github.com/marketplace/actions/aidemo-demo-video)
|
|
20
|
+
[](#three-ways-to-use-it)
|
|
21
|
+
[](https://scorecard.dev/viewer/?uri=github.com/tandryukha/aidemo)
|
|
22
|
+
|
|
23
|
+
**Install:** `/plugin marketplace add tandryukha/aidemo` (Claude Code) · `uses: tandryukha/aidemo@stable` (CI) · `npx -y github:tandryukha/aidemo#stable` (CLI / any agent)
|
|
24
|
+
|
|
25
|
+
[](https://github.com/tandryukha/aidemo/releases/download/v0.3.0/wikipedia-showcase-demo.mp4)
|
|
26
|
+
|
|
27
|
+
<sub>Real output — a ~51 s self-narrated tour of Wikipedia (portal search →
|
|
28
|
+
Ada Lovelace → focus-zoom → click through to the Analytical Engine → glide
|
|
29
|
+
scroll), authored by Claude from one `storyboard.json` and recorded as a
|
|
30
|
+
deterministic replay. The preview GIF is silent;
|
|
31
|
+
**[watch the full version with narration ▶](https://github.com/tandryukha/aidemo/releases/download/v0.3.0/wikipedia-showcase-demo.mp4)**.</sub>
|
|
32
|
+
|
|
33
|
+
## Three ways to use it
|
|
34
|
+
|
|
35
|
+
1. **From your coding agent** — the fastest path. In **Claude Code**:
|
|
36
|
+
`/plugin marketplace add tandryukha/aidemo` then
|
|
37
|
+
`/plugin install record-demo@aidemo` (bundles the skill **and** the MCP
|
|
38
|
+
server). In **Codex / Gemini / any MCP agent**:
|
|
39
|
+
`npx -y github:tandryukha/aidemo#stable repo-init`. Then just say
|
|
40
|
+
*"record a 45s demo of <flow>"* and the agent authors + renders it.
|
|
41
|
+
2. **Locally, free & offline** —
|
|
42
|
+
`AIDEMO_TTS_PROVIDER=local aidemo render <dir> --headless`. An in-process
|
|
43
|
+
voice model + script-timed captions mean **no API key, ~$0, fully offline**.
|
|
44
|
+
See [docs/LOCAL_MODELS.md](docs/LOCAL_MODELS.md).
|
|
45
|
+
3. **In CI, self-maintaining** — drop `uses: tandryukha/aidemo@stable` into a
|
|
46
|
+
workflow. When the product changes, it replays the committed storyboard and
|
|
47
|
+
commits fresh media — **no key, no LLM tokens, ~$0** on free runner minutes.
|
|
48
|
+
See [docs/CI.md](docs/CI.md).
|
|
49
|
+
|
|
50
|
+
**Free & open source.** MIT-licensed. Runs on GitHub's free Actions tier, or
|
|
51
|
+
fully local at $0 with the in-process voice — no API key, no cloud upload, no
|
|
52
|
+
telemetry. Works against **localhost and auth-walled apps** (your own Chrome).
|
|
53
|
+
|
|
54
|
+
## From one sentence to a narrated MP4
|
|
55
|
+
|
|
56
|
+
You type a sentence, the agent writes an artifact you can read and edit, the
|
|
57
|
+
engine records and cuts it:
|
|
58
|
+
|
|
59
|
+
**1 · What you type** — one line to any MCP-capable agent (Claude Code here):
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
claude "record a 45s demo touring Wikipedia: search for Ada Lovelace,
|
|
63
|
+
open the Analytical Engine, then glide down the article"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**2 · What the agent authors** — a plain, editable `storyboard.json` (excerpt:
|
|
67
|
+
narration + a fixed browser action-spec, side by side — no generated code):
|
|
68
|
+
|
|
69
|
+
```jsonc
|
|
70
|
+
{
|
|
71
|
+
"title": "A quick tour of Wikipedia",
|
|
72
|
+
"zoom": {}, // Screen-Studio-style auto-zoom
|
|
73
|
+
"scenes": [
|
|
74
|
+
{ "id": "search",
|
|
75
|
+
"narration": "Start at the Wikipedia portal and search for Ada Lovelace.",
|
|
76
|
+
"actions": [
|
|
77
|
+
{ "op": "goto", "url": "https://www.wikipedia.org/" },
|
|
78
|
+
{ "op": "type", "target": { "selector": "#searchInput" }, "text": "Ada Lovelace" },
|
|
79
|
+
{ "op": "click", "target": { "selector": "button[type=submit]" } } ] },
|
|
80
|
+
{ "id": "engine",
|
|
81
|
+
"narration": "Her notes on Babbage's Analytical Engine hold the first computer program.",
|
|
82
|
+
"actions": [
|
|
83
|
+
{ "op": "focus", "target": { "selector": "#firstHeading" } },
|
|
84
|
+
{ "op": "click", "target": { "selector": "a[href*='Analytical_Engine']" } },
|
|
85
|
+
{ "op": "scrollBy", "dy": 900, "easing": "glide" } ] }
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**3 · How it's recorded + cut** — `aidemo render` drives a real Chrome (smooth
|
|
91
|
+
animated cursor, human-cadence typing, auto-zoom), then trims the dead time and
|
|
92
|
+
syncs to the narration:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
storyboard.json
|
|
96
|
+
→ voice OpenAI / ElevenLabs / local TTS → audio/narration.mp3 + voice.json
|
|
97
|
+
→ record drives Chrome, animated cursor → recordings/raw.{webm,mp4} + timeline.json
|
|
98
|
+
→ captions Whisper word timestamps → generated/captions.{srt,vtt,cues.json}
|
|
99
|
+
→ compose trim idle · sync · auto-zoom · cards · caption · mux → output/final-demo.mp4
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**4 · What you get** — `output/final-demo.mp4`, plus a README-ready GIF
|
|
103
|
+
(`aidemo gif`) and named stills (`aidemo stills`) from the same take. UI changed?
|
|
104
|
+
Re-run against the same storyboard — no re-recording by hand.
|
|
105
|
+
|
|
106
|
+
The design goal: demos that look **human-made and snappy**, not like an AI
|
|
107
|
+
clicking around and waiting between screenshots — by separating **authoring**
|
|
108
|
+
(slow, one-time — figure out the flow) from **recording** (a fast deterministic
|
|
109
|
+
replay with a smooth animated cursor).
|
|
110
|
+
|
|
111
|
+
## What teams render with it
|
|
112
|
+
|
|
113
|
+
- **GitHub README demos** — `aidemo gif demos/onboarding`, drop the autoplaying
|
|
114
|
+
GIF into the readme (the GIFs on this page are exactly that).
|
|
115
|
+
- **Landing-page hero videos** — the muted-autoplay MP4 on
|
|
116
|
+
[aidemo.top](https://aidemo.top) is a rendered demo, poster frame and all.
|
|
117
|
+
- **Release / what-shipped demos** — narrate the new feature, then
|
|
118
|
+
`gh release upload v1.4.0 demos/whats-new/output/final-demo.mp4`.
|
|
119
|
+
- **Customer & prospect demos** — personalized flows against your real app:
|
|
120
|
+
localhost, auth walls, your own logged-in Chrome; nothing leaves the machine.
|
|
121
|
+
|
|
122
|
+
## Render in CI (self-maintaining demos)
|
|
123
|
+
|
|
124
|
+
Commit a storyboard and the **[aidemo GitHub Action](docs/CI.md)** keeps its
|
|
125
|
+
demo media in sync — a fresh narrated, captioned MP4 (and GIF) on every relevant
|
|
126
|
+
change. Deterministic replay + a local voice mean **no API key, no LLM tokens,
|
|
127
|
+
about $0** (just free runner minutes). It's the loop a screen recorder can't
|
|
128
|
+
run: your demo maintains itself.
|
|
129
|
+
|
|
130
|
+
```yaml
|
|
131
|
+
# .github/workflows/demo.yml
|
|
132
|
+
- uses: actions/checkout@v4
|
|
133
|
+
- run: sudo apt-get update && sudo apt-get install -y ffmpeg # ubuntu ships Chrome, not ffmpeg
|
|
134
|
+
- uses: tandryukha/aidemo@stable
|
|
135
|
+
with:
|
|
136
|
+
demos: demos/*
|
|
137
|
+
tts: local # in-process voice → no keys, no tokens
|
|
138
|
+
gif: "true"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Full recipe, templates (auto-commit / PR-comment / cron-refresh), and the
|
|
142
|
+
always-fresh-embeds trick: **[docs/CI.md](docs/CI.md)**,
|
|
143
|
+
**[docs/EMBEDS.md](docs/EMBEDS.md)**, **[docs/recipes/](docs/recipes/)**.
|
|
144
|
+
|
|
145
|
+
## Quick start (self-contained smoke test)
|
|
146
|
+
|
|
147
|
+
A bundled fixture store (search → results → cart → checkout) that renders a
|
|
148
|
+
finished demo with zero external dependencies:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npm install # Node 20+, system Chrome, ffmpeg on PATH
|
|
152
|
+
node examples/local-demo/serve.mjs # terminal 1: fixture on :8787
|
|
153
|
+
node bin/aidemo.mjs render examples/local-demo --headless # terminal 2
|
|
154
|
+
open examples/local-demo/output/final-demo.mp4 # xdg-open on Linux, start on Windows
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Voice/captions need `OPENAI_API_KEY` in `.env` — **or** `AIDEMO_TTS_PROVIDER=local`
|
|
158
|
+
(no key, offline), **or** `OPENAI_BASE_URL` at a local server. See
|
|
159
|
+
[docs/LOCAL_MODELS.md](docs/LOCAL_MODELS.md). No Playwright browser download is
|
|
160
|
+
needed — the engine uses your system Chrome (`channel: "chrome"`).
|
|
161
|
+
|
|
162
|
+
[](https://github.com/tandryukha/aidemo/releases/download/v0.3.0/quickstart-demo.mp4)
|
|
163
|
+
|
|
164
|
+
<sub>The bundled fixture rendered end-to-end — narrated, captioned, auto-trimmed.
|
|
165
|
+
Silent preview; **[full version ▶](https://github.com/tandryukha/aidemo/releases/download/v0.3.0/quickstart-demo.mp4)**.</sub>
|
|
166
|
+
|
|
167
|
+
## CLI
|
|
168
|
+
|
|
169
|
+
Each step is independently runnable and re-runnable — regenerate voice without
|
|
170
|
+
re-recording, recompose without re-transcribing, etc.
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
aidemo init <name> # scaffold demos/<name>/ with a starter storyboard
|
|
174
|
+
aidemo voice <dir> # per-scene TTS → narration.mp3 + voice.json
|
|
175
|
+
aidemo record <dir> # drive Chrome → raw video + timeline.json
|
|
176
|
+
aidemo probe <dir> # record-only dry run (verify selectors), no key needed
|
|
177
|
+
aidemo captions <dir> # Whisper → captions.{srt,vtt,cues.json} (--offline for no network)
|
|
178
|
+
aidemo compose <dir> # trim + sync + zoom + cards + caption + mux → final-demo.mp4
|
|
179
|
+
aidemo gif <dir> # final-demo.mp4 → README-ready GIF (autoplays on GitHub)
|
|
180
|
+
aidemo render <dir> # voice → record → captions → compose
|
|
181
|
+
aidemo guide # print the canonical authoring guide
|
|
182
|
+
aidemo doctor # check Node, ffmpeg, Chrome, voice endpoint
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Add `--headless` for CI/fixtures; omit it for real sites that need your
|
|
186
|
+
logged-in session. `--profile <dir>` picks the Chrome user-data dir;
|
|
187
|
+
`--capture native|obs` switches to high-fidelity screen capture. `voice`/`render`
|
|
188
|
+
**skip TTS for unchanged scenes**, and `record` **salvages a failed take** (keeps
|
|
189
|
+
the footage + drops a screenshot/frame-dump in `logs/`).
|
|
190
|
+
|
|
191
|
+
## Agent interface (MCP)
|
|
192
|
+
|
|
193
|
+
`aidemo mcp` runs a **stdio** MCP server (no network listener) exposing the engine
|
|
194
|
+
to any MCP client. The Claude Code plugin bundles it; `aidemo repo-init` registers
|
|
195
|
+
it agent-neutrally (`.mcp.json` for Claude Code, `.gemini/settings.json` for
|
|
196
|
+
Gemini; `codex mcp add aidemo -- npx -y github:tandryukha/aidemo#stable mcp` for
|
|
197
|
+
Codex).
|
|
198
|
+
|
|
199
|
+
- **Authoring tools** — `get_authoring_guide` serves
|
|
200
|
+
[docs/AUTHORING.md](docs/AUTHORING.md) version-matched from the engine (can't go
|
|
201
|
+
stale); `get_storyboard_schema`, `validate_storyboard`, `init_demo`, `doctor`.
|
|
202
|
+
- **Pipeline tools run as jobs** — `probe`/`record`/`render`/`voice`/`captions`/
|
|
203
|
+
`compose`/`gif` return a `jobId` immediately; `job_status` reports stage,
|
|
204
|
+
per-scene progress, and (on failure) the screenshot/frame-dump paths.
|
|
205
|
+
|
|
206
|
+
## Why it's built this way
|
|
207
|
+
|
|
208
|
+
- **Deterministic replay, not an LLM in the loop.** The recording runs a fixed
|
|
209
|
+
action-spec at full speed, so the video is smooth. The agent only *authors* the
|
|
210
|
+
storyboard (and confirms selectors once), never during capture.
|
|
211
|
+
- **Declarative action-spec + fixed player** (not generated `spec.ts`). Safer,
|
|
212
|
+
editable, and it emits a **timeline** for free — compose fits each scene's video
|
|
213
|
+
to its narration by trimming/speeding only the idle parts, freeze-holding a
|
|
214
|
+
static page for any remainder instead of ugly slow-motion.
|
|
215
|
+
- **Captions via overlaid PNGs, not libass.** Many ffmpeg builds lack
|
|
216
|
+
`subtitles`/`drawtext`; aidemo rasterizes each caption with headless Chrome and
|
|
217
|
+
overlays it with time-gated `enable` — works on any ffmpeg with `overlay`.
|
|
218
|
+
- **Cinematic polish is compose-time, not record-time** — a bad zoom is a
|
|
219
|
+
recompose, never a re-record. See [docs/POLISH.md](docs/POLISH.md).
|
|
220
|
+
|
|
221
|
+
## Deeper docs
|
|
222
|
+
|
|
223
|
+
- **[docs/AUTHORING.md](docs/AUTHORING.md)** — the canonical storyboard schema,
|
|
224
|
+
action vocabulary, and demo-director principles (served by the engine).
|
|
225
|
+
- **[docs/LOCAL_MODELS.md](docs/LOCAL_MODELS.md)** — no-key rendering: in-process
|
|
226
|
+
Kokoro voice, local speech servers (speaches), ElevenLabs, offline captions.
|
|
227
|
+
- **[docs/POLISH.md](docs/POLISH.md)** — auto-zoom, scroll easing, music ducking,
|
|
228
|
+
intro/outro cards, motion blur, cursor control, native/OBS high-fidelity capture.
|
|
229
|
+
- **[docs/CHATGPT_APPS.md](docs/CHATGPT_APPS.md)** — recording ChatGPT Apps SDK
|
|
230
|
+
widgets (dedicated profile, nested iframes, `waitForWidget`).
|
|
231
|
+
- **[docs/CI.md](docs/CI.md)** · **[docs/EMBEDS.md](docs/EMBEDS.md)** · **[docs/recipes/](docs/recipes/)** — CI rendering, always-fresh embeds, agent-in-CI recipes.
|
|
232
|
+
|
|
233
|
+
## Setup
|
|
234
|
+
|
|
235
|
+
Prereqs: **Node 20+**, **Google Chrome**, **ffmpeg + ffprobe** on `PATH`.
|
|
236
|
+
Developed and tested on macOS; Linux works for the default (Playwright) capture
|
|
237
|
+
and `--capture obs`. Run `aidemo doctor` to check your setup.
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
npm install
|
|
241
|
+
cp .env.example .env # add OPENAI_API_KEY, or use AIDEMO_TTS_PROVIDER=local (no key)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Project layout (per demo)
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
demos/<name>/ ← your working area (untracked; scaffold with `aidemo init`)
|
|
248
|
+
input/ brief.md
|
|
249
|
+
generated/ storyboard.json timeline.json captions.{srt,vtt,cues.json}
|
|
250
|
+
recordings/ raw.webm (or raw.mp4 for native/OBS capture)
|
|
251
|
+
audio/ scene-*.mp3 narration.mp3 voice.json
|
|
252
|
+
output/ final-demo.mp4
|
|
253
|
+
logs/ <command>.log fail-<scene>-<n>.{png,json} (on a failed action)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Security & trust
|
|
257
|
+
|
|
258
|
+
- **No telemetry, no analytics, no install-time scripts** (`package.json` has no
|
|
259
|
+
`postinstall`/`preinstall`).
|
|
260
|
+
- **Network is user-initiated only:** `api.openai.com` (only `voice`/`captions`,
|
|
261
|
+
your key — or a local server via `OPENAI_BASE_URL`), `api.elevenlabs.io` (opt-in),
|
|
262
|
+
`huggingface.co` (download-only, once, for `AIDEMO_TTS_PROVIDER=local`), and
|
|
263
|
+
`github.com` (your own `gh`, for `aidemo feedback`). Recording/composing are
|
|
264
|
+
fully local. The MCP server is **stdio-only** — no listener.
|
|
265
|
+
- **Small, auditable surface:** ~20 source files, 7 runtime deps, MIT. Pin an
|
|
266
|
+
immutable ref if you're wary of the moving `#stable` tag:
|
|
267
|
+
`npx -y github:tandryukha/aidemo#v0.8.0`.
|
|
268
|
+
- Full detail: [docs/LOCAL_MODELS.md](docs/LOCAL_MODELS.md#what-leaves-the-machine)
|
|
269
|
+
· report vulnerabilities privately per [SECURITY.md](SECURITY.md).
|
|
270
|
+
|
|
271
|
+
## Roadmap
|
|
272
|
+
|
|
273
|
+
- **Comments on the video** (pause & comment) and **in-place transcript editing**:
|
|
274
|
+
captions map to scenes, so editing a line marks that scene dirty and
|
|
275
|
+
`aidemo voice --scene <id>` + `compose` regenerates only the delta.
|
|
276
|
+
- **Web UI**, project history, brand kits, changelog integrations.
|
|
277
|
+
- **Hosted public MCP** (see [docs/plans/public-mcp.md](docs/plans/public-mcp.md)).
|
|
278
|
+
|
|
279
|
+
Shipped: the **GitHub Action** (CI re-render), cinematic polish (auto-zoom,
|
|
280
|
+
scroll easing, music ducking, intro/outro cards, motion blur, post-hoc cursor
|
|
281
|
+
control), native/OBS capture, the agent-neutral **MCP server** + authoring guide,
|
|
282
|
+
ElevenLabs and **in-process local voice** providers, and the **Claude Code plugin**.
|
|
283
|
+
|
|
284
|
+
## Contributing
|
|
285
|
+
|
|
286
|
+
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, the
|
|
287
|
+
smoke test, and the DCO sign-off requirement. Recording-session feedback has a fast
|
|
288
|
+
path: `aidemo feedback demos/<name>` pre-fills a structured issue.
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
[MIT](LICENSE) © Andrii Taran
|
package/bin/aidemo.mjs
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Thin launcher so `aidemo` runs the TypeScript CLI via tsx without a build step.
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { dirname, resolve } from "node:path";
|
|
8
|
+
|
|
9
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const cli = resolve(here, "..", "src", "cli.ts");
|
|
11
|
+
const require = createRequire(import.meta.url);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Resolve tsx's CLI entry via Node's module resolution so it works both from a
|
|
15
|
+
* local checkout (tsx under the repo's node_modules) AND from a hoisted
|
|
16
|
+
* `npx github:tandryukha/aidemo@stable` install, where npm lifts tsx into a
|
|
17
|
+
* parent node_modules that `<pkg>/node_modules/.bin/tsx` would miss.
|
|
18
|
+
*/
|
|
19
|
+
function findTsxBin() {
|
|
20
|
+
try {
|
|
21
|
+
// Walk up from tsx's resolved entry to its package.json, then read its bin.
|
|
22
|
+
let dir = dirname(require.resolve("tsx"));
|
|
23
|
+
for (let i = 0; i < 6 && dir !== dirname(dir); i++) {
|
|
24
|
+
const pj = resolve(dir, "package.json");
|
|
25
|
+
if (existsSync(pj)) {
|
|
26
|
+
const pkg = require(pj);
|
|
27
|
+
if (pkg.name === "tsx" && pkg.bin) {
|
|
28
|
+
const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin.tsx;
|
|
29
|
+
if (binRel) return resolve(dir, binRel);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
dir = dirname(dir);
|
|
33
|
+
}
|
|
34
|
+
} catch {
|
|
35
|
+
/* fall through to the local .bin guess */
|
|
36
|
+
}
|
|
37
|
+
const local = resolve(here, "..", "node_modules", ".bin", "tsx");
|
|
38
|
+
return existsSync(local) ? local : null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const tsxBin = findTsxBin();
|
|
42
|
+
if (!tsxBin) {
|
|
43
|
+
console.error(
|
|
44
|
+
"aidemo: could not locate the 'tsx' runtime. Run `npm install` in the engine, " +
|
|
45
|
+
"or invoke via `npx -y github:tandryukha/aidemo@stable <cmd>`."
|
|
46
|
+
);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const res = spawnSync(process.execPath, [tsxBin, cli, ...process.argv.slice(2)], {
|
|
51
|
+
stdio: "inherit",
|
|
52
|
+
});
|
|
53
|
+
process.exit(res.status ?? 1);
|